home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkCanvArc.c < prev    next >
C/C++ Source or Header  |  1995-06-08  |  52KB  |  1,721 lines

  1. /* 
  2.  * tkCanvArc.c --
  3.  *
  4.  *    This file implements arc items for canvas widgets.
  5.  *
  6.  * Copyright (c) 1992-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  */
  12.  
  13. static char sccsid[] = "@(#) tkCanvArc.c 1.26 95/06/07 22:53:15";
  14.  
  15. #include <stdio.h>
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18.  
  19. /*
  20.  * The structure below defines the record for each arc item.
  21.  */
  22.  
  23. typedef struct ArcItem  {
  24.     Tk_Item header;        /* Generic stuff that's the same for all
  25.                  * types.  MUST BE FIRST IN STRUCTURE. */
  26.     double bbox[4];        /* Coordinates (x1, y1, x2, y2) of bounding
  27.                  * box for oval of which arc is a piece. */
  28.     double start;        /* Angle at which arc begins, in degrees
  29.                  * between 0 and 360. */
  30.     double extent;        /* Extent of arc (angular distance from
  31.                  * start to end of arc) in degrees between
  32.                  * -360 and 360. */
  33.     double *outlinePtr;        /* Points to (x,y) coordinates for points
  34.                  * that define one or two closed polygons
  35.                  * representing the portion of the outline
  36.                  * that isn't part of the arc (the V-shape
  37.                  * for a pie slice or a line-like segment
  38.                  * for a chord).  Malloc'ed. */
  39.     int numOutlinePoints;    /* Number of points at outlinePtr.  Zero
  40.                  * means no space allocated. */
  41.     int width;            /* Width of outline (in pixels). */
  42.     XColor *outlineColor;    /* Color for outline.  NULL means don't
  43.                  * draw outline. */
  44.     XColor *fillColor;        /* Color for filling arc (used for drawing
  45.                  * outline too when style is "arc").  NULL
  46.                  * means don't fill arc. */
  47.     Pixmap fillStipple;        /* Stipple bitmap for filling item. */
  48.     Pixmap outlineStipple;    /* Stipple bitmap for outline. */
  49.     Tk_Uid style;        /* How to draw arc: arc, chord, or pieslice. */
  50.     GC outlineGC;        /* Graphics context for outline. */
  51.     GC fillGC;            /* Graphics context for filling item. */
  52.     double center1[2];        /* Coordinates of center of arc outline at
  53.                  * start (see ComputeArcOutline). */
  54.     double center2[2];        /* Coordinates of center of arc outline at
  55.                  * start+extent (see ComputeArcOutline). */
  56. } ArcItem;
  57.  
  58. /*
  59.  * The definitions below define the sizes of the polygons used to
  60.  * display outline information for various styles of arcs:
  61.  */
  62.  
  63. #define CHORD_OUTLINE_PTS    7
  64. #define PIE_OUTLINE1_PTS    6
  65. #define PIE_OUTLINE2_PTS    7
  66.  
  67. /*
  68.  * Information used for parsing configuration specs:
  69.  */
  70.  
  71. static Tk_ConfigSpec configSpecs[] = {
  72.     {TK_CONFIG_DOUBLE, "-extent", (char *) NULL, (char *) NULL,
  73.     "90", Tk_Offset(ArcItem, extent), TK_CONFIG_DONT_SET_DEFAULT},
  74.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  75.     (char *) NULL, Tk_Offset(ArcItem, fillColor), TK_CONFIG_NULL_OK},
  76.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  77.     "black", Tk_Offset(ArcItem, outlineColor), TK_CONFIG_NULL_OK},
  78.     {TK_CONFIG_BITMAP, "-outlinestipple", (char *) NULL, (char *) NULL,
  79.     (char *) NULL, Tk_Offset(ArcItem, outlineStipple), TK_CONFIG_NULL_OK},
  80.     {TK_CONFIG_DOUBLE, "-start", (char *) NULL, (char *) NULL,
  81.     "0", Tk_Offset(ArcItem, start), TK_CONFIG_DONT_SET_DEFAULT},
  82.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  83.     (char *) NULL, Tk_Offset(ArcItem, fillStipple), TK_CONFIG_NULL_OK},
  84.     {TK_CONFIG_UID, "-style", (char *) NULL, (char *) NULL,
  85.     "pieslice", Tk_Offset(ArcItem, style), TK_CONFIG_DONT_SET_DEFAULT},
  86.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  87.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tk_CanvasTagsOption},
  88.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  89.     "1", Tk_Offset(ArcItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  90.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  91.     (char *) NULL, 0, 0}
  92. };
  93.  
  94. /*
  95.  * Prototypes for procedures defined in this file:
  96.  */
  97.  
  98. static void        ComputeArcBbox _ANSI_ARGS_((Tk_Canvas canvas,
  99.                 ArcItem *arcPtr));
  100. static int        ConfigureArc _ANSI_ARGS_((Tcl_Interp *interp,
  101.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  102.                 char **argv, int flags));
  103. static int        CreateArc _ANSI_ARGS_((Tcl_Interp *interp,
  104.                 Tk_Canvas canvas, struct Tk_Item *itemPtr,
  105.                 int argc, char **argv));
  106. static void        DeleteArc _ANSI_ARGS_((Tk_Canvas canvas,
  107.                 Tk_Item *itemPtr, Display *display));
  108. static void        DisplayArc _ANSI_ARGS_((Tk_Canvas canvas,
  109.                 Tk_Item *itemPtr, Display *display, Drawable dst,
  110.                 int x, int y, int width, int height));
  111. static int        ArcCoords _ANSI_ARGS_((Tcl_Interp *interp,
  112.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  113.                 char **argv));
  114. static int        ArcToArea _ANSI_ARGS_((Tk_Canvas canvas,
  115.                 Tk_Item *itemPtr, double *rectPtr));
  116. static double        ArcToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  117.                 Tk_Item *itemPtr, double *coordPtr));
  118. static int        ArcToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  119.                 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  120. static void        ScaleArc _ANSI_ARGS_((Tk_Canvas canvas,
  121.                 Tk_Item *itemPtr, double originX, double originY,
  122.                 double scaleX, double scaleY));
  123. static void        TranslateArc _ANSI_ARGS_((Tk_Canvas canvas,
  124.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  125. static int        AngleInRange _ANSI_ARGS_((double x, double y,
  126.                 double start, double extent));
  127. static void        ComputeArcOutline _ANSI_ARGS_((ArcItem *arcPtr));
  128. static int        HorizLineToArc _ANSI_ARGS_((double x1, double x2,
  129.                 double y, double rx, double ry,
  130.                 double start, double extent));
  131. static int        VertLineToArc _ANSI_ARGS_((double x, double y1,
  132.                 double y2, double rx, double ry,
  133.                 double start, double extent));
  134.  
  135. /*
  136.  * The structures below defines the arc item types by means of procedures
  137.  * that can be invoked by generic item code.
  138.  */
  139.  
  140. Tk_ItemType tkArcType = {
  141.     "arc",                /* name */
  142.     sizeof(ArcItem),            /* itemSize */
  143.     CreateArc,                /* createProc */
  144.     configSpecs,            /* configSpecs */
  145.     ConfigureArc,            /* configureProc */
  146.     ArcCoords,                /* coordProc */
  147.     DeleteArc,                /* deleteProc */
  148.     DisplayArc,                /* displayProc */
  149.     0,                    /* alwaysRedraw */
  150.     ArcToPoint,                /* pointProc */
  151.     ArcToArea,                /* areaProc */
  152.     ArcToPostscript,            /* postscriptProc */
  153.     ScaleArc,                /* scaleProc */
  154.     TranslateArc,            /* translateProc */
  155.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  156.     (Tk_ItemCursorProc *) NULL,        /* icursorProc */
  157.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  158.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  159.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  160.     (Tk_ItemType *) NULL        /* nextPtr */
  161. };
  162.  
  163. #ifndef PI
  164. #    define PI 3.14159265358979323846
  165. #endif
  166.  
  167. /*
  168.  * The uid's below comprise the legal values for the "-style"
  169.  * option for arcs.
  170.  */
  171.  
  172. static Tk_Uid arcUid =  NULL;
  173. static Tk_Uid chordUid =  NULL;
  174. static Tk_Uid pieSliceUid = NULL;
  175.  
  176. /*
  177.  *--------------------------------------------------------------
  178.  *
  179.  * CreateArc --
  180.  *
  181.  *    This procedure is invoked to create a new arc item in
  182.  *    a canvas.
  183.  *
  184.  * Results:
  185.  *    A standard Tcl return value.  If an error occurred in
  186.  *    creating the item, then an error message is left in
  187.  *    interp->result;  in this case itemPtr is
  188.  *    left uninitialized, so it can be safely freed by the
  189.  *    caller.
  190.  *
  191.  * Side effects:
  192.  *    A new arc item is created.
  193.  *
  194.  *--------------------------------------------------------------
  195.  */
  196.  
  197. static int
  198. CreateArc(interp, canvas, itemPtr, argc, argv)
  199.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  200.     Tk_Canvas canvas;            /* Canvas to hold new item. */
  201.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  202.                      * has been initialized by caller. */
  203.     int argc;                /* Number of arguments in argv. */
  204.     char **argv;            /* Arguments describing arc. */
  205. {
  206.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  207.  
  208.     if (argc < 4) {
  209.     Tcl_AppendResult(interp, "wrong # args:  should be \"",
  210.         Tk_PathName(Tk_CanvasTkwin(canvas)), "\" create ",
  211.         itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?",
  212.         (char *) NULL);
  213.     return TCL_ERROR;
  214.     }
  215.  
  216.     /*
  217.      * Carry out once-only initialization.
  218.      */
  219.  
  220.     if (arcUid == NULL) {
  221.     arcUid = Tk_GetUid("arc");
  222.     chordUid = Tk_GetUid("chord");
  223.     pieSliceUid = Tk_GetUid("pieslice");
  224.     }
  225.  
  226.     /*
  227.      * Carry out initialization that is needed in order to clean
  228.      * up after errors during the the remainder of this procedure.
  229.      */
  230.  
  231.     arcPtr->start = 0;
  232.     arcPtr->extent = 90;
  233.     arcPtr->outlinePtr = NULL;
  234.     arcPtr->numOutlinePoints = 0;
  235.     arcPtr->width = 1;
  236.     arcPtr->outlineColor = NULL;
  237.     arcPtr->fillColor = NULL;
  238.     arcPtr->fillStipple = None;
  239.     arcPtr->outlineStipple = None;
  240.     arcPtr->style = pieSliceUid;
  241.     arcPtr->outlineGC = None;
  242.     arcPtr->fillGC = None;
  243.  
  244.     /*
  245.      * Process the arguments to fill in the item record.
  246.      */
  247.  
  248.     if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &arcPtr->bbox[0]) != TCL_OK)
  249.         || (Tk_CanvasGetCoord(interp, canvas, argv[1],
  250.         &arcPtr->bbox[1]) != TCL_OK)
  251.         || (Tk_CanvasGetCoord(interp, canvas, argv[2],
  252.             &arcPtr->bbox[2]) != TCL_OK)
  253.         || (Tk_CanvasGetCoord(interp, canvas, argv[3],
  254.             &arcPtr->bbox[3]) != TCL_OK)) {
  255.     return TCL_ERROR;
  256.     }
  257.  
  258.     if (ConfigureArc(interp, canvas, itemPtr, argc-4, argv+4, 0) != TCL_OK) {
  259.     DeleteArc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  260.     return TCL_ERROR;
  261.     }
  262.     return TCL_OK;
  263. }
  264.  
  265. /*
  266.  *--------------------------------------------------------------
  267.  *
  268.  * ArcCoords --
  269.  *
  270.  *    This procedure is invoked to process the "coords" widget
  271.  *    command on arcs.  See the user documentation for details
  272.  *    on what it does.
  273.  *
  274.  * Results:
  275.  *    Returns TCL_OK or TCL_ERROR, and sets interp->result.
  276.  *
  277.  * Side effects:
  278.  *    The coordinates for the given item may be changed.
  279.  *
  280.  *--------------------------------------------------------------
  281.  */
  282.  
  283. static int
  284. ArcCoords(interp, canvas, itemPtr, argc, argv)
  285.     Tcl_Interp *interp;            /* Used for error reporting. */
  286.     Tk_Canvas canvas;            /* Canvas containing item. */
  287.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  288.                      * read or modified. */
  289.     int argc;                /* Number of coordinates supplied in
  290.                      * argv. */
  291.     char **argv;            /* Array of coordinates: x1, y1,
  292.                      * x2, y2, ... */
  293. {
  294.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  295.     char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE];
  296.     char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE];
  297.  
  298.     if (argc == 0) {
  299.     Tcl_PrintDouble(interp, arcPtr->bbox[0], c0);
  300.     Tcl_PrintDouble(interp, arcPtr->bbox[1], c1);
  301.     Tcl_PrintDouble(interp, arcPtr->bbox[2], c2);
  302.     Tcl_PrintDouble(interp, arcPtr->bbox[3], c3);
  303.     Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3,
  304.         (char *) NULL);
  305.     } else if (argc == 4) {
  306.     if ((Tk_CanvasGetCoord(interp, canvas, argv[0],
  307.             &arcPtr->bbox[0]) != TCL_OK)
  308.         || (Tk_CanvasGetCoord(interp, canvas, argv[1],
  309.             &arcPtr->bbox[1]) != TCL_OK)
  310.         || (Tk_CanvasGetCoord(interp, canvas, argv[2],
  311.             &arcPtr->bbox[2]) != TCL_OK)
  312.         || (Tk_CanvasGetCoord(interp, canvas, argv[3],
  313.             &arcPtr->bbox[3]) != TCL_OK)) {
  314.         return TCL_ERROR;
  315.     }
  316.     ComputeArcBbox(canvas, arcPtr);
  317.     } else {
  318.     sprintf(interp->result,
  319.         "wrong # coordinates:  expected 0 or 4, got %d",
  320.         argc);
  321.     return TCL_ERROR;
  322.     }
  323.     return TCL_OK;
  324. }
  325.  
  326. /*
  327.  *--------------------------------------------------------------
  328.  *
  329.  * ConfigureArc --
  330.  *
  331.  *    This procedure is invoked to configure various aspects
  332.  *    of a arc item, such as its outline and fill colors.
  333.  *
  334.  * Results:
  335.  *    A standard Tcl result code.  If an error occurs, then
  336.  *    an error message is left in interp->result.
  337.  *
  338.  * Side effects:
  339.  *    Configuration information, such as colors and stipple
  340.  *    patterns, may be set for itemPtr.
  341.  *
  342.  *--------------------------------------------------------------
  343.  */
  344.  
  345. static int
  346. ConfigureArc(interp, canvas, itemPtr, argc, argv, flags)
  347.     Tcl_Interp *interp;        /* Used for error reporting. */
  348.     Tk_Canvas canvas;        /* Canvas containing itemPtr. */
  349.     Tk_Item *itemPtr;        /* Arc item to reconfigure. */
  350.     int argc;            /* Number of elements in argv.  */
  351.     char **argv;        /* Arguments describing things to configure. */
  352.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  353. {
  354.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  355.     XGCValues gcValues;
  356.     GC newGC;
  357.     unsigned long mask;
  358.     int i;
  359.     Tk_Window tkwin;
  360.  
  361.     tkwin = Tk_CanvasTkwin(canvas);
  362.     if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv,
  363.         (char *) arcPtr, flags) != TCL_OK) {
  364.     return TCL_ERROR;
  365.     }
  366.  
  367.     /*
  368.      * A few of the options require additional processing, such as
  369.      * style and graphics contexts.
  370.      */
  371.  
  372.     i = arcPtr->start/360.0;
  373.     arcPtr->start -= i*360.0;
  374.     if (arcPtr->start < 0) {
  375.     arcPtr->start += 360.0;
  376.     }
  377.     i = arcPtr->extent/360.0;
  378.     arcPtr->extent -= i*360.0;
  379.  
  380.     if ((arcPtr->style != arcUid) && (arcPtr->style != chordUid)
  381.         && (arcPtr->style != pieSliceUid)) {
  382.     Tcl_AppendResult(interp, "bad -style option \"",
  383.         arcPtr->style, "\": must be arc, chord, or pieslice",
  384.         (char *) NULL);
  385.     arcPtr->style = pieSliceUid;
  386.     return TCL_ERROR;
  387.     }
  388.  
  389.     if (arcPtr->width < 0) {
  390.     arcPtr->width = 1;
  391.     }
  392.     if (arcPtr->outlineColor == NULL) {
  393.     newGC = None;
  394.     } else {
  395.     gcValues.foreground = arcPtr->outlineColor->pixel;
  396.     gcValues.cap_style = CapButt;
  397.     gcValues.line_width = arcPtr->width;
  398.     mask = GCForeground|GCCapStyle|GCLineWidth;
  399.     if (arcPtr->outlineStipple != None) {
  400.         gcValues.stipple = arcPtr->outlineStipple;
  401.         gcValues.fill_style = FillStippled;
  402.         mask |= GCStipple|GCFillStyle;
  403.     }
  404.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  405.     }
  406.     if (arcPtr->outlineGC != None) {
  407.     Tk_FreeGC(Tk_Display(tkwin), arcPtr->outlineGC);
  408.     }
  409.     arcPtr->outlineGC = newGC;
  410.  
  411.     if ((arcPtr->fillColor == NULL) || (arcPtr->style == arcUid)) {
  412.     newGC = None;
  413.     } else {
  414.     gcValues.foreground = arcPtr->fillColor->pixel;
  415.     if (arcPtr->style == chordUid) {
  416.         gcValues.arc_mode = ArcChord;
  417.     } else {
  418.         gcValues.arc_mode = ArcPieSlice;
  419.     }
  420.     mask = GCForeground|GCArcMode;
  421.     if (arcPtr->fillStipple != None) {
  422.         gcValues.stipple = arcPtr->fillStipple;
  423.         gcValues.fill_style = FillStippled;
  424.         mask |= GCStipple|GCFillStyle;
  425.     }
  426.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  427.     }
  428.     if (arcPtr->fillGC != None) {
  429.     Tk_FreeGC(Tk_Display(tkwin), arcPtr->fillGC);
  430.     }
  431.     arcPtr->fillGC = newGC;
  432.  
  433.     ComputeArcBbox(canvas, arcPtr);
  434.     return TCL_OK;
  435. }
  436.  
  437. /*
  438.  *--------------------------------------------------------------
  439.  *
  440.  * DeleteArc --
  441.  *
  442.  *    This procedure is called to clean up the data structure
  443.  *    associated with a arc item.
  444.  *
  445.  * Results:
  446.  *    None.
  447.  *
  448.  * Side effects:
  449.  *    Resources associated with itemPtr are released.
  450.  *
  451.  *--------------------------------------------------------------
  452.  */
  453.  
  454. static void
  455. DeleteArc(canvas, itemPtr, display)
  456.     Tk_Canvas canvas;            /* Info about overall canvas. */
  457.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  458.     Display *display;            /* Display containing window for
  459.                      * canvas. */
  460. {
  461.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  462.  
  463.     if (arcPtr->numOutlinePoints != 0) {
  464.     ckfree((char *) arcPtr->outlinePtr);
  465.     }
  466.     if (arcPtr->outlineColor != NULL) {
  467.     Tk_FreeColor(arcPtr->outlineColor);
  468.     }
  469.     if (arcPtr->fillColor != NULL) {
  470.     Tk_FreeColor(arcPtr->fillColor);
  471.     }
  472.     if (arcPtr->fillStipple != None) {
  473.     Tk_FreeBitmap(display, arcPtr->fillStipple);
  474.     }
  475.     if (arcPtr->outlineStipple != None) {
  476.     Tk_FreeBitmap(display, arcPtr->outlineStipple);
  477.     }
  478.     if (arcPtr->outlineGC != None) {
  479.     Tk_FreeGC(display, arcPtr->outlineGC);
  480.     }
  481.     if (arcPtr->fillGC != None) {
  482.     Tk_FreeGC(display, arcPtr->fillGC);
  483.     }
  484. }
  485.  
  486. /*
  487.  *--------------------------------------------------------------
  488.  *
  489.  * ComputeArcBbox --
  490.  *
  491.  *    This procedure is invoked to compute the bounding box of
  492.  *    all the pixels that may be drawn as part of an arc.
  493.  *
  494.  * Results:
  495.  *    None.
  496.  *
  497.  * Side effects:
  498.  *    The fields x1, y1, x2, and y2 are updated in the header
  499.  *    for itemPtr.
  500.  *
  501.  *--------------------------------------------------------------
  502.  */
  503.  
  504.     /* ARGSUSED */
  505. static void
  506. ComputeArcBbox(canvas, arcPtr)
  507.     Tk_Canvas canvas;            /* Canvas that contains item. */
  508.     ArcItem *arcPtr;            /* Item whose bbox is to be
  509.                      * recomputed. */
  510. {
  511.     double tmp, center[2], point[2];
  512.  
  513.     /*
  514.      * Make sure that the first coordinates are the lowest ones.
  515.      */
  516.  
  517.     if (arcPtr->bbox[1] > arcPtr->bbox[3]) {
  518.     double tmp;
  519.     tmp = arcPtr->bbox[3];
  520.     arcPtr->bbox[3] = arcPtr->bbox[1];
  521.     arcPtr->bbox[1] = tmp;
  522.     }
  523.     if (arcPtr->bbox[0] > arcPtr->bbox[2]) {
  524.     double tmp;
  525.     tmp = arcPtr->bbox[2];
  526.     arcPtr->bbox[2] = arcPtr->bbox[0];
  527.     arcPtr->bbox[0] = tmp;
  528.     }
  529.  
  530.     ComputeArcOutline(arcPtr);
  531.  
  532.     /*
  533.      * To compute the bounding box, start with the the bbox formed
  534.      * by the two endpoints of the arc.  Then add in the center of
  535.      * the arc's oval (if relevant) and the 3-o'clock, 6-o'clock,
  536.      * 9-o'clock, and 12-o'clock positions, if they are relevant.
  537.      */
  538.  
  539.     arcPtr->header.x1 = arcPtr->header.x2 = arcPtr->center1[0];
  540.     arcPtr->header.y1 = arcPtr->header.y2 = arcPtr->center1[1];
  541.     TkIncludePoint((Tk_Item *) arcPtr, arcPtr->center2);
  542.     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2;
  543.     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2;
  544.     if (arcPtr->style != arcUid) {
  545.     TkIncludePoint((Tk_Item *) arcPtr, center);
  546.     }
  547.  
  548.     tmp = -arcPtr->start;
  549.     if (tmp < 0) {
  550.     tmp += 360.0;
  551.     }
  552.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  553.     point[0] = arcPtr->bbox[2];
  554.     point[1] = center[1];
  555.     TkIncludePoint((Tk_Item *) arcPtr, point);
  556.     }
  557.     tmp = 90.0 - arcPtr->start;
  558.     if (tmp < 0) {
  559.     tmp += 360.0;
  560.     }
  561.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  562.     point[0] = center[0];
  563.     point[1] = arcPtr->bbox[1];
  564.     TkIncludePoint((Tk_Item *) arcPtr, point);
  565.     }
  566.     tmp = 180.0 - arcPtr->start;
  567.     if (tmp < 0) {
  568.     tmp += 360.0;
  569.     }
  570.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  571.     point[0] = arcPtr->bbox[0];
  572.     point[1] = center[1];
  573.     TkIncludePoint((Tk_Item *) arcPtr, point);
  574.     }
  575.     tmp = 270.0 - arcPtr->start;
  576.     if (tmp < 0) {
  577.     tmp += 360.0;
  578.     }
  579.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  580.     point[0] = center[0];
  581.     point[1] = arcPtr->bbox[3];
  582.     TkIncludePoint((Tk_Item *) arcPtr, point);
  583.     }
  584.  
  585.     /*
  586.      * Lastly, expand by the width of the arc (if the arc's outline is
  587.      * being drawn) and add one extra pixel just for safety.
  588.      */
  589.  
  590.     if (arcPtr->outlineColor == NULL) {
  591.     tmp = 1;
  592.     } else {
  593.     tmp = (arcPtr->width + 1)/2 + 1;
  594.     }
  595.     arcPtr->header.x1 -= tmp;
  596.     arcPtr->header.y1 -= tmp;
  597.     arcPtr->header.x2 += tmp;
  598.     arcPtr->header.y2 += tmp;
  599. }
  600.  
  601. /*
  602.  *--------------------------------------------------------------
  603.  *
  604.  * DisplayArc --
  605.  *
  606.  *    This procedure is invoked to draw an arc item in a given
  607.  *    drawable.
  608.  *
  609.  * Results:
  610.  *    None.
  611.  *
  612.  * Side effects:
  613.  *    ItemPtr is drawn in drawable using the transformation
  614.  *    information in canvas.
  615.  *
  616.  *--------------------------------------------------------------
  617.  */
  618.  
  619. static void
  620. DisplayArc(canvas, itemPtr, display, drawable, x, y, width, height)
  621.     Tk_Canvas canvas;            /* Canvas that contains item. */
  622.     Tk_Item *itemPtr;            /* Item to be displayed. */
  623.     Display *display;            /* Display on which to draw item. */
  624.     Drawable drawable;            /* Pixmap or window in which to draw
  625.                      * item. */
  626.     int x, y, width, height;        /* Describes region of canvas that
  627.                      * must be redisplayed (not used). */
  628. {
  629.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  630.     short x1, y1, x2, y2;
  631.     int start, extent;
  632.  
  633.     /*
  634.      * Compute the screen coordinates of the bounding box for the item,
  635.      * plus integer values for the angles.
  636.      */
  637.  
  638.     Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[0], arcPtr->bbox[1],
  639.         &x1, &y1);
  640.     Tk_CanvasDrawableCoords(canvas, arcPtr->bbox[2], arcPtr->bbox[3],
  641.         &x2, &y2);
  642.     if (x2 <= x1) {
  643.     x2 = x1+1;
  644.     }
  645.     if (y2 <= y1) {
  646.     y2 = y1+1;
  647.     }
  648.     start = (64*arcPtr->start) + 0.5;
  649.     extent = (64*arcPtr->extent) + 0.5;
  650.  
  651.     /*
  652.      * Display filled arc first (if wanted), then outline.  If the extent
  653.      * is zero then don't invoke XFillArc or XDrawArc, since this causes
  654.      * some window servers to crash and should be a no-op anyway.
  655.      */
  656.  
  657.     if ((arcPtr->fillGC != None) && (extent != 0)) {
  658.     if (arcPtr->fillStipple != None) {
  659.         Tk_CanvasSetStippleOrigin(canvas, arcPtr->fillGC);
  660.     }
  661.     XFillArc(display, drawable, arcPtr->fillGC, x1, y1, (unsigned) (x2-x1),
  662.         (unsigned) (y2-y1), start, extent);
  663.     if (arcPtr->fillStipple != None) {
  664.         XSetTSOrigin(display, arcPtr->fillGC, 0, 0);
  665.     }
  666.     }
  667.     if (arcPtr->outlineGC != None) {
  668.     if (arcPtr->outlineStipple != None) {
  669.         Tk_CanvasSetStippleOrigin(canvas, arcPtr->outlineGC);
  670.     }
  671.     if (extent != 0) {
  672.         XDrawArc(display, drawable, arcPtr->outlineGC, x1, y1,
  673.             (unsigned) (x2-x1), (unsigned) (y2-y1), start, extent);
  674.     }
  675.  
  676.     /*
  677.      * If the outline width is very thin, don't use polygons to draw
  678.      * the linear parts of the outline (this often results in nothing
  679.      * being displayed); just draw lines instead.
  680.      */
  681.  
  682.     if (arcPtr->width <= 2) {
  683.         Tk_CanvasDrawableCoords(canvas, arcPtr->center1[0],
  684.             arcPtr->center1[1], &x1, &y1);
  685.         Tk_CanvasDrawableCoords(canvas, arcPtr->center2[0],
  686.             arcPtr->center2[1], &x2, &y2);
  687.  
  688.         if (arcPtr->style == chordUid) {
  689.         XDrawLine(display, drawable, arcPtr->outlineGC,
  690.             x1, y1, x2, y2);
  691.         } else if (arcPtr->style == pieSliceUid) {
  692.         short cx, cy;
  693.  
  694.         Tk_CanvasDrawableCoords(canvas,
  695.             (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0,
  696.             (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0, &cx, &cy);
  697.         XDrawLine(display, drawable, arcPtr->outlineGC,
  698.             cx, cy, x1, y1);
  699.         XDrawLine(display, drawable, arcPtr->outlineGC,
  700.             cx, cy, x2, y2);
  701.         }
  702.     } else {
  703.         if (arcPtr->style == chordUid) {
  704.         TkFillPolygon(canvas, arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  705.             display, drawable, arcPtr->outlineGC, None);
  706.         } else if (arcPtr->style == pieSliceUid) {
  707.         TkFillPolygon(canvas, arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  708.             display, drawable, arcPtr->outlineGC, None);
  709.         TkFillPolygon(canvas, arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  710.             PIE_OUTLINE2_PTS, display, drawable, arcPtr->outlineGC,
  711.             None);
  712.         }
  713.     }
  714.     if (arcPtr->outlineStipple != None) {
  715.         XSetTSOrigin(display, arcPtr->outlineGC, 0, 0);
  716.     }
  717.     }
  718. }
  719.  
  720. /*
  721.  *--------------------------------------------------------------
  722.  *
  723.  * ArcToPoint --
  724.  *
  725.  *    Computes the distance from a given point to a given
  726.  *    arc, in canvas units.
  727.  *
  728.  * Results:
  729.  *    The return value is 0 if the point whose x and y coordinates
  730.  *    are coordPtr[0] and coordPtr[1] is inside the arc.  If the
  731.  *    point isn't inside the arc then the return value is the
  732.  *    distance from the point to the arc.  If itemPtr is filled,
  733.  *    then anywhere in the interior is considered "inside"; if
  734.  *    itemPtr isn't filled, then "inside" means only the area
  735.  *    occupied by the outline.
  736.  *
  737.  * Side effects:
  738.  *    None.
  739.  *
  740.  *--------------------------------------------------------------
  741.  */
  742.  
  743.     /* ARGSUSED */
  744. static double
  745. ArcToPoint(canvas, itemPtr, pointPtr)
  746.     Tk_Canvas canvas;        /* Canvas containing item. */
  747.     Tk_Item *itemPtr;        /* Item to check against point. */
  748.     double *pointPtr;        /* Pointer to x and y coordinates. */
  749. {
  750.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  751.     double vertex[2], pointAngle, diff, dist, newDist;
  752.     double poly[8], polyDist, width, t1, t2;
  753.     int filled, angleInRange;
  754.  
  755.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  756.     filled = 1;
  757.     } else {
  758.     filled = 0;
  759.     }
  760.  
  761.     /*
  762.      * See if the point is within the angular range of the arc.
  763.      * Remember, X angles are backwards from the way we'd normally
  764.      * think of them.  Also, compensate for any eccentricity of
  765.      * the oval.
  766.      */
  767.  
  768.     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  769.     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  770.     t1 = (pointPtr[1] - vertex[1])/(arcPtr->bbox[3] - arcPtr->bbox[1]);
  771.     t2 = (pointPtr[0] - vertex[0])/(arcPtr->bbox[2] - arcPtr->bbox[0]);
  772.     if ((t1 == 0.0) && (t2 == 0.0)) {
  773.     pointAngle = 0;
  774.     } else {
  775.     pointAngle = -atan2(t1, t2)*180/PI;
  776.     }
  777.     diff = pointAngle - arcPtr->start;
  778.     diff -= ((int) (diff/360.0) * 360.0);
  779.     if (diff < 0) {
  780.     diff += 360.0;
  781.     }
  782.     angleInRange = (diff <= arcPtr->extent) ||
  783.         ((arcPtr->extent < 0) && ((diff - 360.0) >= arcPtr->extent));
  784.  
  785.     /*
  786.      * Now perform different tests depending on what kind of arc
  787.      * we're dealing with.
  788.      */
  789.  
  790.     if (arcPtr->style == arcUid) {
  791.     if (angleInRange) {
  792.         return TkOvalToPoint(arcPtr->bbox, (double) arcPtr->width,
  793.             0, pointPtr);
  794.     }
  795.     dist = hypot(pointPtr[0] - arcPtr->center1[0],
  796.         pointPtr[1] - arcPtr->center1[1]);
  797.     newDist = hypot(pointPtr[0] - arcPtr->center2[0],
  798.         pointPtr[1] - arcPtr->center2[1]);
  799.     if (newDist < dist) {
  800.         return newDist;
  801.     }
  802.     return dist;
  803.     }
  804.  
  805.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  806.     filled = 1;
  807.     } else {
  808.     filled = 0;
  809.     }
  810.     if (arcPtr->outlineGC == None) {
  811.     width = 0.0;
  812.     } else {
  813.     width = arcPtr->width;
  814.     }
  815.  
  816.     if (arcPtr->style == pieSliceUid) {
  817.     if (width > 1.0) {
  818.         dist = TkPolygonToPoint(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  819.             pointPtr);
  820.         newDist = TkPolygonToPoint(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  821.             PIE_OUTLINE2_PTS, pointPtr);
  822.     } else {
  823.         dist = TkLineToPoint(vertex, arcPtr->center1, pointPtr);
  824.         newDist = TkLineToPoint(vertex, arcPtr->center2, pointPtr);
  825.     }
  826.     if (newDist < dist) {
  827.         dist = newDist;
  828.     }
  829.     if (angleInRange) {
  830.         newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
  831.         if (newDist < dist) {
  832.         dist = newDist;
  833.         }
  834.     }
  835.     return dist;
  836.     }
  837.  
  838.     /*
  839.      * This is a chord-style arc.  We have to deal specially with the
  840.      * triangular piece that represents the difference between a
  841.      * chord-style arc and a pie-slice arc (for small angles this piece
  842.      * is excluded here where it would be included for pie slices;
  843.      * for large angles the piece is included here but would be
  844.      * excluded for pie slices).
  845.      */
  846.  
  847.     if (width > 1.0) {
  848.     dist = TkPolygonToPoint(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  849.             pointPtr);
  850.     } else {
  851.     dist = TkLineToPoint(arcPtr->center1, arcPtr->center2, pointPtr);
  852.     }
  853.     poly[0] = poly[6] = vertex[0];
  854.     poly[1] = poly[7] = vertex[1];
  855.     poly[2] = arcPtr->center1[0];
  856.     poly[3] = arcPtr->center1[1];
  857.     poly[4] = arcPtr->center2[0];
  858.     poly[5] = arcPtr->center2[1];
  859.     polyDist = TkPolygonToPoint(poly, 4, pointPtr);
  860.     if (angleInRange) {
  861.     if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)
  862.         || (polyDist > 0.0)) {
  863.         newDist = TkOvalToPoint(arcPtr->bbox, width, filled, pointPtr);
  864.         if (newDist < dist) {
  865.         dist = newDist;
  866.         }
  867.     }
  868.     } else {
  869.     if ((arcPtr->extent < -180.0) || (arcPtr->extent > 180.0)) {
  870.         if (filled && (polyDist < dist)) {
  871.         dist = polyDist;
  872.         }
  873.     }
  874.     }
  875.     return dist;
  876. }
  877.  
  878. /*
  879.  *--------------------------------------------------------------
  880.  *
  881.  * ArcToArea --
  882.  *
  883.  *    This procedure is called to determine whether an item
  884.  *    lies entirely inside, entirely outside, or overlapping
  885.  *    a given area.
  886.  *
  887.  * Results:
  888.  *    -1 is returned if the item is entirely outside the area
  889.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  890.  *    inside the given area.
  891.  *
  892.  * Side effects:
  893.  *    None.
  894.  *
  895.  *--------------------------------------------------------------
  896.  */
  897.  
  898.     /* ARGSUSED */
  899. static int
  900. ArcToArea(canvas, itemPtr, rectPtr)
  901.     Tk_Canvas canvas;        /* Canvas containing item. */
  902.     Tk_Item *itemPtr;        /* Item to check against arc. */
  903.     double *rectPtr;        /* Pointer to array of four coordinates
  904.                  * (x1, y1, x2, y2) describing rectangular
  905.                  * area.  */
  906. {
  907.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  908.     double rx, ry;        /* Radii for transformed oval:  these define
  909.                  * an oval centered at the origin. */
  910.     double tRect[4];        /* Transformed version of x1, y1, x2, y2,
  911.                  * for coord. system where arc is centered
  912.                  * on the origin. */
  913.     double center[2], width, angle, tmp;
  914.     double points[20], *pointPtr;
  915.     int numPoints, filled;
  916.     int inside;            /* Non-zero means every test so far suggests
  917.                  * that arc is inside rectangle.  0 means
  918.                  * every test so far shows arc to be outside
  919.                  * of rectangle. */
  920.     int newInside;
  921.  
  922.     if ((arcPtr->fillGC != None) || (arcPtr->outlineGC == None)) {
  923.     filled = 1;
  924.     } else {
  925.     filled = 0;
  926.     }
  927.     if (arcPtr->outlineGC == None) {
  928.     width = 0.0;
  929.     } else {
  930.     width = arcPtr->width;
  931.     }
  932.  
  933.     /*
  934.      * Transform both the arc and the rectangle so that the arc's oval
  935.      * is centered on the origin.
  936.      */
  937.  
  938.     center[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  939.     center[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  940.     tRect[0] = rectPtr[0] - center[0];
  941.     tRect[1] = rectPtr[1] - center[1];
  942.     tRect[2] = rectPtr[2] - center[0];
  943.     tRect[3] = rectPtr[3] - center[1];
  944.     rx = arcPtr->bbox[2] - center[0] + width/2.0;
  945.     ry = arcPtr->bbox[3] - center[1] + width/2.0;
  946.  
  947.     /*
  948.      * Find the extreme points of the arc and see whether these are all
  949.      * inside the rectangle (in which case we're done), partly in and
  950.      * partly out (in which case we're done), or all outside (in which
  951.      * case we have more work to do).  The extreme points include the
  952.      * following, which are checked in order:
  953.      *
  954.      * 1. The outside points of the arc, corresponding to start and
  955.      *      extent.
  956.      * 2. The center of the arc (but only in pie-slice mode).
  957.      * 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc
  958.      *    includes those angles).
  959.      */
  960.  
  961.     pointPtr = points;
  962.     numPoints = 0;
  963.     angle = -arcPtr->start*(PI/180.0);
  964.     pointPtr[0] = rx*cos(angle);
  965.     pointPtr[1] = ry*sin(angle);
  966.     angle += -arcPtr->extent*(PI/180.0);
  967.     pointPtr[2] = rx*cos(angle);
  968.     pointPtr[3] = ry*sin(angle);
  969.     numPoints = 2;
  970.     pointPtr += 4;
  971.  
  972.     if ((arcPtr->style == pieSliceUid) && (arcPtr->extent < 180.0)) {
  973.     pointPtr[0] = 0.0;
  974.     pointPtr[1] = 0.0;
  975.     numPoints++;
  976.     pointPtr += 2;
  977.     }
  978.  
  979.     tmp = -arcPtr->start;
  980.     if (tmp < 0) {
  981.     tmp += 360.0;
  982.     }
  983.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  984.     pointPtr[0] = rx;
  985.     pointPtr[1] = 0.0;
  986.     numPoints++;
  987.     pointPtr += 2;
  988.     }
  989.     tmp = 90.0 - arcPtr->start;
  990.     if (tmp < 0) {
  991.     tmp += 360.0;
  992.     }
  993.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  994.     pointPtr[0] = 0.0;
  995.     pointPtr[1] = -ry;
  996.     numPoints++;
  997.     pointPtr += 2;
  998.     }
  999.     tmp = 180.0 - arcPtr->start;
  1000.     if (tmp < 0) {
  1001.     tmp += 360.0;
  1002.     }
  1003.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  1004.     pointPtr[0] = -rx;
  1005.     pointPtr[1] = 0.0;
  1006.     numPoints++;
  1007.     pointPtr += 2;
  1008.     }
  1009.     tmp = 270.0 - arcPtr->start;
  1010.     if (tmp < 0) {
  1011.     tmp += 360.0;
  1012.     }
  1013.     if ((tmp < arcPtr->extent) || ((tmp-360) > arcPtr->extent)) {
  1014.     pointPtr[0] = 0.0;
  1015.     pointPtr[1] = ry;
  1016.     numPoints++;
  1017.     pointPtr += 2;
  1018.     }
  1019.  
  1020.     /*
  1021.      * Now that we've located the extreme points, loop through them all
  1022.      * to see which are inside the rectangle.
  1023.      */
  1024.  
  1025.     inside = (points[0] > tRect[0]) && (points[0] < tRect[2])
  1026.         && (points[1] > tRect[1]) && (points[1] < tRect[3]);
  1027.     for (pointPtr = points+2; numPoints > 1; pointPtr += 2, numPoints--) {
  1028.     newInside = (pointPtr[0] > tRect[0]) && (pointPtr[0] < tRect[2])
  1029.         && (pointPtr[1] > tRect[1]) && (pointPtr[1] < tRect[3]);
  1030.     if (newInside != inside) {
  1031.         return 0;
  1032.     }
  1033.     }
  1034.  
  1035.     if (inside) {
  1036.     return 1;
  1037.     }
  1038.  
  1039.     /*
  1040.      * So far, oval appears to be outside rectangle, but can't yet tell
  1041.      * for sure.  Next, test each of the four sides of the rectangle
  1042.      * against the bounding region for the arc.  If any intersections
  1043.      * are found, then return "overlapping".  First, test against the
  1044.      * polygon(s) forming the sides of a chord or pie-slice.
  1045.      */
  1046.  
  1047.     if (arcPtr->style == pieSliceUid) {
  1048.     if (width >= 1.0) {
  1049.         if (TkPolygonToArea(arcPtr->outlinePtr, PIE_OUTLINE1_PTS,
  1050.             rectPtr) != -1)  {
  1051.         return 0;
  1052.         }
  1053.         if (TkPolygonToArea(arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  1054.             PIE_OUTLINE2_PTS, rectPtr) != -1) {
  1055.         return 0;
  1056.         }
  1057.     } else {
  1058.         if ((TkLineToArea(center, arcPtr->center1, rectPtr) != -1) ||
  1059.             (TkLineToArea(center, arcPtr->center2, rectPtr) != -1)) {
  1060.         return 0;
  1061.         }
  1062.     }
  1063.     } else if (arcPtr->style == chordUid) {
  1064.     if (width >= 1.0) {
  1065.         if (TkPolygonToArea(arcPtr->outlinePtr, CHORD_OUTLINE_PTS,
  1066.             rectPtr) != -1) {
  1067.         return 0;
  1068.         }
  1069.     } else {
  1070.         if (TkLineToArea(arcPtr->center1, arcPtr->center2,
  1071.             rectPtr) != -1) {
  1072.         return 0;
  1073.         }
  1074.     }
  1075.     }
  1076.  
  1077.     /*
  1078.      * Next check for overlap between each of the four sides and the
  1079.      * outer perimiter of the arc.  If the arc isn't filled, then also
  1080.      * check the inner perimeter of the arc.
  1081.      */
  1082.  
  1083.     if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
  1084.         arcPtr->extent)
  1085.         || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
  1086.         arcPtr->start, arcPtr->extent)
  1087.         || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
  1088.         arcPtr->start, arcPtr->extent)
  1089.         || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
  1090.         arcPtr->start, arcPtr->extent)) {
  1091.     return 0;
  1092.     }
  1093.     if ((width > 1.0) && !filled) {
  1094.     rx -= width;
  1095.     ry -= width;
  1096.     if (HorizLineToArc(tRect[0], tRect[2], tRect[1], rx, ry, arcPtr->start,
  1097.             arcPtr->extent)
  1098.         || HorizLineToArc(tRect[0], tRect[2], tRect[3], rx, ry,
  1099.             arcPtr->start, arcPtr->extent)
  1100.         || VertLineToArc(tRect[0], tRect[1], tRect[3], rx, ry,
  1101.             arcPtr->start, arcPtr->extent)
  1102.         || VertLineToArc(tRect[2], tRect[1], tRect[3], rx, ry,
  1103.             arcPtr->start, arcPtr->extent)) {
  1104.         return 0;
  1105.     }
  1106.     }
  1107.  
  1108.     /*
  1109.      * The arc still appears to be totally disjoint from the rectangle,
  1110.      * but it's also possible that the rectangle is totally inside the arc.
  1111.      * Do one last check, which is to check one point of the rectangle
  1112.      * to see if it's inside the arc.  If it is, we've got overlap.  If
  1113.      * it isn't, the arc's really outside the rectangle.
  1114.      */
  1115.  
  1116.     if (ArcToPoint(canvas, itemPtr, rectPtr) == 0.0) {
  1117.     return 0;
  1118.     }
  1119.     return -1;
  1120. }
  1121.  
  1122. /*
  1123.  *--------------------------------------------------------------
  1124.  *
  1125.  * ScaleArc --
  1126.  *
  1127.  *    This procedure is invoked to rescale an arc item.
  1128.  *
  1129.  * Results:
  1130.  *    None.
  1131.  *
  1132.  * Side effects:
  1133.  *    The arc referred to by itemPtr is rescaled so that the
  1134.  *    following transformation is applied to all point
  1135.  *    coordinates:
  1136.  *        x' = originX + scaleX*(x-originX)
  1137.  *        y' = originY + scaleY*(y-originY)
  1138.  *
  1139.  *--------------------------------------------------------------
  1140.  */
  1141.  
  1142. static void
  1143. ScaleArc(canvas, itemPtr, originX, originY, scaleX, scaleY)
  1144.     Tk_Canvas canvas;            /* Canvas containing arc. */
  1145.     Tk_Item *itemPtr;            /* Arc to be scaled. */
  1146.     double originX, originY;        /* Origin about which to scale rect. */
  1147.     double scaleX;            /* Amount to scale in X direction. */
  1148.     double scaleY;            /* Amount to scale in Y direction. */
  1149. {
  1150.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  1151.  
  1152.     arcPtr->bbox[0] = originX + scaleX*(arcPtr->bbox[0] - originX);
  1153.     arcPtr->bbox[1] = originY + scaleY*(arcPtr->bbox[1] - originY);
  1154.     arcPtr->bbox[2] = originX + scaleX*(arcPtr->bbox[2] - originX);
  1155.     arcPtr->bbox[3] = originY + scaleY*(arcPtr->bbox[3] - originY);
  1156.     ComputeArcBbox(canvas, arcPtr);
  1157. }
  1158.  
  1159. /*
  1160.  *--------------------------------------------------------------
  1161.  *
  1162.  * TranslateArc --
  1163.  *
  1164.  *    This procedure is called to move an arc by a given amount.
  1165.  *
  1166.  * Results:
  1167.  *    None.
  1168.  *
  1169.  * Side effects:
  1170.  *    The position of the arc is offset by (xDelta, yDelta), and
  1171.  *    the bounding box is updated in the generic part of the item
  1172.  *    structure.
  1173.  *
  1174.  *--------------------------------------------------------------
  1175.  */
  1176.  
  1177. static void
  1178. TranslateArc(canvas, itemPtr, deltaX, deltaY)
  1179.     Tk_Canvas canvas;            /* Canvas containing item. */
  1180.     Tk_Item *itemPtr;            /* Item that is being moved. */
  1181.     double deltaX, deltaY;        /* Amount by which item is to be
  1182.                      * moved. */
  1183. {
  1184.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  1185.  
  1186.     arcPtr->bbox[0] += deltaX;
  1187.     arcPtr->bbox[1] += deltaY;
  1188.     arcPtr->bbox[2] += deltaX;
  1189.     arcPtr->bbox[3] += deltaY;
  1190.     ComputeArcBbox(canvas, arcPtr);
  1191. }
  1192.  
  1193. /*
  1194.  *--------------------------------------------------------------
  1195.  *
  1196.  * ComputeArcOutline --
  1197.  *
  1198.  *    This procedure creates a polygon describing everything in
  1199.  *    the outline for an arc except what's in the curved part.
  1200.  *    For a "pie slice" arc this is a V-shaped chunk, and for
  1201.  *    a "chord" arc this is a linear chunk (with cutaway corners).
  1202.  *    For "arc" arcs, this stuff isn't relevant.
  1203.  *
  1204.  * Results:
  1205.  *    None.
  1206.  *
  1207.  * Side effects:
  1208.  *    The information at arcPtr->outlinePtr gets modified, and
  1209.  *    storage for arcPtr->outlinePtr may be allocated or freed.
  1210.  *
  1211.  *--------------------------------------------------------------
  1212.  */
  1213.  
  1214. static void
  1215. ComputeArcOutline(arcPtr)
  1216.     ArcItem *arcPtr;            /* Information about arc. */
  1217. {
  1218.     double sin1, cos1, sin2, cos2, angle, halfWidth;
  1219.     double boxWidth, boxHeight;
  1220.     double vertex[2], corner1[2], corner2[2];
  1221.     double *outlinePtr;
  1222.  
  1223.     /*
  1224.      * Make sure that the outlinePtr array is large enough to hold
  1225.      * either a chord or pie-slice outline.
  1226.      */
  1227.  
  1228.     if (arcPtr->numOutlinePoints == 0) {
  1229.     arcPtr->outlinePtr = (double *) ckalloc((unsigned)
  1230.         (26 * sizeof(double)));
  1231.     arcPtr->numOutlinePoints = 22;
  1232.     }
  1233.     outlinePtr = arcPtr->outlinePtr;
  1234.  
  1235.     /*
  1236.      * First compute the two points that lie at the centers of
  1237.      * the ends of the curved arc segment, which are marked with
  1238.      * X's in the figure below:
  1239.      *
  1240.      *
  1241.      *                  * * *
  1242.      *                  *          *
  1243.      *               *      * *      *
  1244.      *             *    *         *    *
  1245.      *            *   *             *   *
  1246.      *             X *               * X
  1247.      *
  1248.      * The code is tricky because the arc can be ovular in shape.
  1249.      * It computes the position for a unit circle, and then
  1250.      * scales to fit the shape of the arc's bounding box.
  1251.      *
  1252.      * Also, watch out because angles go counter-clockwise like you
  1253.      * might expect, but the y-coordinate system is inverted.  To
  1254.      * handle this, just negate the angles in all the computations.
  1255.      */
  1256.  
  1257.     boxWidth = arcPtr->bbox[2] - arcPtr->bbox[0];
  1258.     boxHeight = arcPtr->bbox[3] - arcPtr->bbox[1];
  1259.     angle = -arcPtr->start*PI/180.0;
  1260.     sin1 = sin(angle);
  1261.     cos1 = cos(angle);
  1262.     angle -= arcPtr->extent*PI/180.0;
  1263.     sin2 = sin(angle);
  1264.     cos2 = cos(angle);
  1265.     vertex[0] = (arcPtr->bbox[0] + arcPtr->bbox[2])/2.0;
  1266.     vertex[1] = (arcPtr->bbox[1] + arcPtr->bbox[3])/2.0;
  1267.     arcPtr->center1[0] = vertex[0] + cos1*boxWidth/2.0;
  1268.     arcPtr->center1[1] = vertex[1] + sin1*boxHeight/2.0;
  1269.     arcPtr->center2[0] = vertex[0] + cos2*boxWidth/2.0;
  1270.     arcPtr->center2[1] = vertex[1] + sin2*boxHeight/2.0;
  1271.  
  1272.     /*
  1273.      * Next compute the "outermost corners" of the arc, which are
  1274.      * marked with X's in the figure below:
  1275.      *
  1276.      *                  * * *
  1277.      *                  *          *
  1278.      *               *      * *      *
  1279.      *             *    *         *    *
  1280.      *            X   *             *   X
  1281.      *               *               *
  1282.      *
  1283.      * The code below is tricky because it has to handle eccentricity
  1284.      * in the shape of the oval.  The key in the code below is to
  1285.      * realize that the slope of the line from arcPtr->center1 to corner1
  1286.      * is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2
  1287.      * and corner2.  These formulas can be computed from the formula for
  1288.      * the oval.
  1289.      */
  1290.  
  1291.     halfWidth = arcPtr->width/2.0;
  1292.     if (((boxWidth*sin1) == 0.0) && ((boxHeight*cos1) == 0.0)) {
  1293.     angle = 0.0;
  1294.     } else {
  1295.     angle = atan2(boxWidth*sin1, boxHeight*cos1);
  1296.     }
  1297.     corner1[0] = arcPtr->center1[0] + cos(angle)*halfWidth;
  1298.     corner1[1] = arcPtr->center1[1] + sin(angle)*halfWidth;
  1299.     if (((boxWidth*sin2) == 0.0) && ((boxHeight*cos2) == 0.0)) {
  1300.     angle = 0.0;
  1301.     } else {
  1302.     angle = atan2(boxWidth*sin2, boxHeight*cos2);
  1303.     }
  1304.     corner2[0] = arcPtr->center2[0] + cos(angle)*halfWidth;
  1305.     corner2[1] = arcPtr->center2[1] + sin(angle)*halfWidth;
  1306.  
  1307.     /*
  1308.      * For a chord outline, generate a six-sided polygon with three
  1309.      * points for each end of the chord.  The first and third points
  1310.      * for each end are butt points generated on either side of the
  1311.      * center point.  The second point is the corner point.
  1312.      */
  1313.  
  1314.     if (arcPtr->style == chordUid) {
  1315.     outlinePtr[0] = outlinePtr[12] = corner1[0];
  1316.     outlinePtr[1] = outlinePtr[13] = corner1[1];
  1317.     TkGetButtPoints(arcPtr->center2, arcPtr->center1,
  1318.         (double) arcPtr->width, 0, outlinePtr+10, outlinePtr+2);
  1319.     outlinePtr[4] = arcPtr->center2[0] + outlinePtr[2]
  1320.         - arcPtr->center1[0];
  1321.     outlinePtr[5] = arcPtr->center2[1] + outlinePtr[3]
  1322.         - arcPtr->center1[1];
  1323.     outlinePtr[6] = corner2[0];
  1324.     outlinePtr[7] = corner2[1];
  1325.     outlinePtr[8] = arcPtr->center2[0] + outlinePtr[10]
  1326.         - arcPtr->center1[0];
  1327.     outlinePtr[9] = arcPtr->center2[1] + outlinePtr[11]
  1328.         - arcPtr->center1[1];
  1329.     } else if (arcPtr->style == pieSliceUid) {
  1330.     /*
  1331.      * For pie slices, generate two polygons, one for each side
  1332.      * of the pie slice.  The first arm has a shape like this,
  1333.      * where the center of the oval is X, arcPtr->center1 is at Y, and
  1334.      * corner1 is at Z:
  1335.      *
  1336.      *     _____________________
  1337.      *    |              \
  1338.      *    |               \
  1339.      *    X             Y  Z
  1340.      *    |               /
  1341.      *    |_____________________/
  1342.      *
  1343.      */
  1344.  
  1345.     TkGetButtPoints(arcPtr->center1, vertex, (double) arcPtr->width, 0,
  1346.         outlinePtr, outlinePtr+2);
  1347.     outlinePtr[4] = arcPtr->center1[0] + outlinePtr[2] - vertex[0];
  1348.     outlinePtr[5] = arcPtr->center1[1] + outlinePtr[3] - vertex[1];
  1349.     outlinePtr[6] = corner1[0];
  1350.     outlinePtr[7] = corner1[1];
  1351.     outlinePtr[8] = arcPtr->center1[0] + outlinePtr[0] - vertex[0];
  1352.     outlinePtr[9] = arcPtr->center1[1] + outlinePtr[1] - vertex[1];
  1353.     outlinePtr[10] = outlinePtr[0];
  1354.     outlinePtr[11] = outlinePtr[1];
  1355.  
  1356.     /*
  1357.      * The second arm has a shape like this:
  1358.      *
  1359.      *
  1360.      *       ______________________
  1361.      *      /              \
  1362.      *     /               \
  1363.      *    Z  Y            X  /
  1364.      *     \              /
  1365.      *      \______________________/
  1366.      *
  1367.      * Similar to above X is the center of the oval/circle, Y is
  1368.      * arcPtr->center2, and Z is corner2.  The extra jog out to the left
  1369.      * of X is needed in or to produce a butted joint with the
  1370.      * first arm;  the corner to the right of X is one of the
  1371.      * first two points of the first arm, depending on extent.
  1372.      */
  1373.  
  1374.     TkGetButtPoints(arcPtr->center2, vertex, (double) arcPtr->width, 0,
  1375.         outlinePtr+12, outlinePtr+16);
  1376.     if ((arcPtr->extent > 180) ||
  1377.         ((arcPtr->extent < 0) && (arcPtr->extent > -180))) {
  1378.         outlinePtr[14] = outlinePtr[0];
  1379.         outlinePtr[15] = outlinePtr[1];
  1380.     } else {
  1381.         outlinePtr[14] = outlinePtr[2];
  1382.         outlinePtr[15] = outlinePtr[3];
  1383.     }
  1384.     outlinePtr[18] = arcPtr->center2[0] + outlinePtr[16] - vertex[0];
  1385.     outlinePtr[19] = arcPtr->center2[1] + outlinePtr[17] - vertex[1];
  1386.     outlinePtr[20] = corner2[0];
  1387.     outlinePtr[21] = corner2[1];
  1388.     outlinePtr[22] = arcPtr->center2[0] + outlinePtr[12] - vertex[0];
  1389.     outlinePtr[23] = arcPtr->center2[1] + outlinePtr[13] - vertex[1];
  1390.     outlinePtr[24] = outlinePtr[12];
  1391.     outlinePtr[25] = outlinePtr[13];
  1392.     }
  1393. }
  1394.  
  1395. /*
  1396.  *--------------------------------------------------------------
  1397.  *
  1398.  * HorizLineToArc --
  1399.  *
  1400.  *    Determines whether a horizontal line segment intersects
  1401.  *    a given arc.
  1402.  *
  1403.  * Results:
  1404.  *    The return value is 1 if the given line intersects the
  1405.  *    infinitely-thin arc section defined by rx, ry, start,
  1406.  *    and extent, and 0 otherwise.  Only the perimeter of the
  1407.  *    arc is checked: interior areas (e.g. pie-slice or chord)
  1408.  *    are not checked.
  1409.  *
  1410.  * Side effects:
  1411.  *    None.
  1412.  *
  1413.  *--------------------------------------------------------------
  1414.  */
  1415.  
  1416. static int
  1417. HorizLineToArc(x1, x2, y, rx, ry, start, extent)
  1418.     double x1, x2;        /* X-coords of endpoints of line segment. 
  1419.                  * X1 must be <= x2. */
  1420.     double y;            /* Y-coordinate of line segment. */
  1421.     double rx, ry;        /* These x- and y-radii define an oval
  1422.                  * centered at the origin. */
  1423.     double start, extent;    /* Angles that define extent of arc, in
  1424.                  * the standard fashion for this module. */
  1425. {
  1426.     double tmp;
  1427.     double tx, ty;        /* Coordinates of intersection point in
  1428.                  * transformed coordinate system. */
  1429.     double x;
  1430.  
  1431.     /*
  1432.      * Compute the x-coordinate of one possible intersection point
  1433.      * between the arc and the line.  Use a transformed coordinate
  1434.      * system where the oval is a unit circle centered at the origin.
  1435.      * Then scale back to get actual x-coordinate.
  1436.      */
  1437.  
  1438.     ty = y/ry;
  1439.     tmp = 1 - ty*ty;
  1440.     if (tmp < 0) {
  1441.     return 0;
  1442.     }
  1443.     tx = sqrt(tmp);
  1444.     x = tx*rx;
  1445.  
  1446.     /*
  1447.      * Test both intersection points.
  1448.      */
  1449.  
  1450.     if ((x >= x1) && (x <= x2) && AngleInRange(tx, ty, start, extent)) {
  1451.     return 1;
  1452.     }
  1453.     if ((-x >= x1) && (-x <= x2) && AngleInRange(-tx, ty, start, extent)) {
  1454.     return 1;
  1455.     }
  1456.     return 0;
  1457. }
  1458.  
  1459. /*
  1460.  *--------------------------------------------------------------
  1461.  *
  1462.  * VertLineToArc --
  1463.  *
  1464.  *    Determines whether a vertical line segment intersects
  1465.  *    a given arc.
  1466.  *
  1467.  * Results:
  1468.  *    The return value is 1 if the given line intersects the
  1469.  *    infinitely-thin arc section defined by rx, ry, start,
  1470.  *    and extent, and 0 otherwise.  Only the perimeter of the
  1471.  *    arc is checked: interior areas (e.g. pie-slice or chord)
  1472.  *    are not checked.
  1473.  *
  1474.  * Side effects:
  1475.  *    None.
  1476.  *
  1477.  *--------------------------------------------------------------
  1478.  */
  1479.  
  1480. static int
  1481. VertLineToArc(x, y1, y2, rx, ry, start, extent)
  1482.     double x;            /* X-coordinate of line segment. */
  1483.     double y1, y2;        /* Y-coords of endpoints of line segment. 
  1484.                  * Y1 must be <= y2. */
  1485.     double rx, ry;        /* These x- and y-radii define an oval
  1486.                  * centered at the origin. */
  1487.     double start, extent;    /* Angles that define extent of arc, in
  1488.                  * the standard fashion for this module. */
  1489. {
  1490.     double tmp;
  1491.     double tx, ty;        /* Coordinates of intersection point in
  1492.                  * transformed coordinate system. */
  1493.     double y;
  1494.  
  1495.     /*
  1496.      * Compute the y-coordinate of one possible intersection point
  1497.      * between the arc and the line.  Use a transformed coordinate
  1498.      * system where the oval is a unit circle centered at the origin.
  1499.      * Then scale back to get actual y-coordinate.
  1500.      */
  1501.  
  1502.     tx = x/rx;
  1503.     tmp = 1 - tx*tx;
  1504.     if (tmp < 0) {
  1505.     return 0;
  1506.     }
  1507.     ty = sqrt(tmp);
  1508.     y = ty*ry;
  1509.  
  1510.     /*
  1511.      * Test both intersection points.
  1512.      */
  1513.  
  1514.     if ((y > y1) && (y < y2) && AngleInRange(tx, ty, start, extent)) {
  1515.     return 1;
  1516.     }
  1517.     if ((-y > y1) && (-y < y2) && AngleInRange(tx, -ty, start, extent)) {
  1518.     return 1;
  1519.     }
  1520.     return 0;
  1521. }
  1522.  
  1523. /*
  1524.  *--------------------------------------------------------------
  1525.  *
  1526.  * AngleInRange --
  1527.  *
  1528.  *    Determine whether the angle from the origin to a given
  1529.  *    point is within a given range.
  1530.  *
  1531.  * Results:
  1532.  *    The return value is 1 if the angle from (0,0) to (x,y)
  1533.  *    is in the range given by start and extent, where angles
  1534.  *    are interpreted in the standard way for ovals (meaning
  1535.  *    backwards from normal interpretation).  Otherwise the
  1536.  *    return value is 0.
  1537.  *
  1538.  * Side effects:
  1539.  *    None.
  1540.  *
  1541.  *--------------------------------------------------------------
  1542.  */
  1543.  
  1544. static int
  1545. AngleInRange(x, y, start, extent)
  1546.     double x, y;        /* Coordinate of point;  angle measured
  1547.                  * from origin to here, relative to x-axis. */
  1548.     double start;        /* First angle, degrees, >=0, <=360. */
  1549.     double extent;        /* Size of arc in degrees >=-360, <=360. */
  1550. {
  1551.     double diff;
  1552.  
  1553.     if ((x == 0.0) && (y == 0.0)) {
  1554.     return 1;
  1555.     }
  1556.     diff = -atan2(y, x);
  1557.     diff = diff*(180.0/PI) - start;
  1558.     while (diff > 360.0) {
  1559.     diff -= 360.0;
  1560.     }
  1561.     while (diff < 0.0) {
  1562.     diff += 360.0;
  1563.     }
  1564.     if (extent >= 0) {
  1565.     return diff <= extent;
  1566.     }
  1567.     return (diff-360.0) >= extent;
  1568. }
  1569.  
  1570. /*
  1571.  *--------------------------------------------------------------
  1572.  *
  1573.  * ArcToPostscript --
  1574.  *
  1575.  *    This procedure is called to generate Postscript for
  1576.  *    arc items.
  1577.  *
  1578.  * Results:
  1579.  *    The return value is a standard Tcl result.  If an error
  1580.  *    occurs in generating Postscript then an error message is
  1581.  *    left in interp->result, replacing whatever used
  1582.  *    to be there.  If no error occurs, then Postscript for the
  1583.  *    item is appended to the result.
  1584.  *
  1585.  * Side effects:
  1586.  *    None.
  1587.  *
  1588.  *--------------------------------------------------------------
  1589.  */
  1590.  
  1591. static int
  1592. ArcToPostscript(interp, canvas, itemPtr, prepass)
  1593.     Tcl_Interp *interp;            /* Leave Postscript or error message
  1594.                      * here. */
  1595.     Tk_Canvas canvas;            /* Information about overall canvas. */
  1596.     Tk_Item *itemPtr;            /* Item for which Postscript is
  1597.                      * wanted. */
  1598.     int prepass;            /* 1 means this is a prepass to
  1599.                      * collect font information;  0 means
  1600.                      * final Postscript is being created. */
  1601. {
  1602.     ArcItem *arcPtr = (ArcItem *) itemPtr;
  1603.     char buffer[400];
  1604.     double y1, y2, ang1, ang2;
  1605.  
  1606.     y1 = Tk_CanvasPsY(canvas, arcPtr->bbox[1]);
  1607.     y2 = Tk_CanvasPsY(canvas, arcPtr->bbox[3]);
  1608.     ang1 = arcPtr->start;
  1609.     ang2 = ang1 + arcPtr->extent;
  1610.     if (ang2 < ang1) {
  1611.     ang1 = ang2;
  1612.     ang2 = arcPtr->start;
  1613.     }
  1614.  
  1615.     /*
  1616.      * If the arc is filled, output Postscript for the interior region
  1617.      * of the arc.
  1618.      */
  1619.  
  1620.     if (arcPtr->fillGC != None) {
  1621.     sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n",
  1622.         (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2,
  1623.         (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2);
  1624.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1625.     if (arcPtr->style == chordUid) {
  1626.         sprintf(buffer, "0 0 1 %.15g %.15g arc closepath\nsetmatrix\n",
  1627.             ang1, ang2);
  1628.     } else {
  1629.         sprintf(buffer,
  1630.             "0 0 moveto 0 0 1 %.15g %.15g arc closepath\nsetmatrix\n",
  1631.             ang1, ang2);
  1632.     }
  1633.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1634.     if (Tk_CanvasPsColor(interp, canvas, arcPtr->fillColor) != TCL_OK) {
  1635.         return TCL_ERROR;
  1636.     };
  1637.     if (arcPtr->fillStipple != None) {
  1638.         Tcl_AppendResult(interp, "clip ", (char *) NULL);
  1639.         if (Tk_CanvasPsStipple(interp, canvas, arcPtr->fillStipple)
  1640.             != TCL_OK) {
  1641.         return TCL_ERROR;
  1642.         }
  1643.         if (arcPtr->outlineGC != None) {
  1644.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  1645.         }
  1646.     } else {
  1647.         Tcl_AppendResult(interp, "fill\n", (char *) NULL);
  1648.     }
  1649.     }
  1650.  
  1651.     /*
  1652.      * If there's an outline for the arc, draw it.
  1653.      */
  1654.  
  1655.     if (arcPtr->outlineGC != None) {
  1656.     sprintf(buffer, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale\n",
  1657.         (arcPtr->bbox[0] + arcPtr->bbox[2])/2, (y1 + y2)/2,
  1658.         (arcPtr->bbox[2] - arcPtr->bbox[0])/2, (y1 - y2)/2);
  1659.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1660.     sprintf(buffer, "0 0 1 %.15g %.15g arc\nsetmatrix\n", ang1, ang2);
  1661.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1662.     sprintf(buffer, "%d setlinewidth\n0 setlinecap\n", arcPtr->width);
  1663.     Tcl_AppendResult(interp, buffer, (char *) NULL);
  1664.     if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor)
  1665.         != TCL_OK) {
  1666.         return TCL_ERROR;
  1667.     }
  1668.     if (arcPtr->outlineStipple != None) {
  1669.         Tcl_AppendResult(interp, "StrokeClip ", (char *) NULL);
  1670.         if (Tk_CanvasPsStipple(interp, canvas,
  1671.             arcPtr->outlineStipple) != TCL_OK) {
  1672.         return TCL_ERROR;
  1673.         }
  1674.     } else {
  1675.         Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
  1676.     }
  1677.     if (arcPtr->style != arcUid) {
  1678.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  1679.         if (arcPtr->style == chordUid) {
  1680.         Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr,
  1681.             CHORD_OUTLINE_PTS);
  1682.         } else {
  1683.         Tk_CanvasPsPath(interp, canvas, arcPtr->outlinePtr,
  1684.             PIE_OUTLINE1_PTS);
  1685.         if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor)
  1686.             != TCL_OK) {
  1687.             return TCL_ERROR;
  1688.         }
  1689.         if (arcPtr->outlineStipple != None) {
  1690.             Tcl_AppendResult(interp, "clip ", (char *) NULL);
  1691.             if (Tk_CanvasPsStipple(interp, canvas,
  1692.                 arcPtr->outlineStipple) != TCL_OK) {
  1693.             return TCL_ERROR;
  1694.             }
  1695.         } else {
  1696.             Tcl_AppendResult(interp, "fill\n", (char *) NULL);
  1697.         }
  1698.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  1699.         Tk_CanvasPsPath(interp, canvas,
  1700.             arcPtr->outlinePtr + 2*PIE_OUTLINE1_PTS,
  1701.             PIE_OUTLINE2_PTS);
  1702.         }
  1703.         if (Tk_CanvasPsColor(interp, canvas, arcPtr->outlineColor)
  1704.             != TCL_OK) {
  1705.         return TCL_ERROR;
  1706.         }
  1707.         if (arcPtr->outlineStipple != None) {
  1708.         Tcl_AppendResult(interp, "clip ", (char *) NULL);
  1709.         if (Tk_CanvasPsStipple(interp, canvas,
  1710.             arcPtr->outlineStipple) != TCL_OK) {
  1711.             return TCL_ERROR;
  1712.         }
  1713.         } else {
  1714.         Tcl_AppendResult(interp, "fill\n", (char *) NULL);
  1715.         }
  1716.     }
  1717.     }
  1718.  
  1719.     return TCL_OK;
  1720. }
  1721.